home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Camelot / Camelot 105 (1991-02)(Swedish User Group of Amiga)(SE)(PD)[WB].zip / Camelot 105 (1991-02)(Swedish User Group of Amiga)(SE)(PD)[WB].adf / AmigaUUCP / dnews / display.c < prev    next >
C/C++ Source or Header  |  1991-02-08  |  14KB  |  662 lines

  1.  
  2. /*
  3.  *  DISPLAY.C
  4.  *
  5.  *  This module handles all display windows.
  6.  *
  7.  */
  8.  
  9. #include <exec/types.h>
  10. #include "defs.h"
  11. #include <intuition/intuition.h>
  12.  
  13. Prototype int getyn(char *);
  14. Prototype void *OpenBrowseDisplay(char *, char *, short);
  15. Prototype void SetBrowseTitle(void *, char *);
  16. Prototype void CloseBrowseDisplay(void *);
  17. Prototype void ChangeBrowseDisplay(void *, char *, char *);
  18. Prototype int WaitBrowseEvent(void **, int *, int *);
  19. Prototype void    LoadDisplayConfig(void);
  20. Prototype void    SaveDisplayConfig(void);
  21. Prototype void    RefreshBrowseDisplay(void *);
  22.  
  23. Local void TabExpand(char *, short);
  24.  
  25.  
  26.  
  27. #define MAXCONF 3
  28.  
  29. typedef struct Window        Window;
  30. typedef struct NewWindow    NewWindow;
  31. typedef struct IntuiMessage IMsg;
  32.  
  33. typedef struct Display {
  34.     struct Display *Next;
  35.     Window  *Win;        /*    associated window    */
  36.     char    *Name;        /*    name of file        */
  37.     char    *Title;        /*    window title        */
  38.     FILE    *Fi;        /*    file pointer        */
  39.     long    WMask;        /*    wait mask for window    */
  40.     short   Id;         /*    config id        */
  41.     short   FlagRefresh;
  42.     short   ColStart;
  43.     long    FirstNonHdrLine;/*    first non-header line    */
  44.  
  45.     long    TLineNo;        /*    line # for top line    */
  46.     long    TPos;        /*    position (top line)     */
  47.     long    BPos;        /*    position (bottom line)  */
  48.     long    XPos;        /*    end of file (or scan)   */
  49.     long    WLines;        /*    lines displayed in win    */
  50.     long    WMaxLines;        /*    maximum #lines in window*/
  51.     long    FLines;        /*    lines in file if known    */
  52. } Display;
  53.  
  54. typedef struct Config {
  55.     short   TopEdge;
  56.     short   LeftEdge;
  57.     short   Width;
  58.     short   Height;
  59. } Config;
  60.  
  61. static long    WMask;       /*  Window mask       */
  62. static Display *CachDisp;  /*  last display that had an event           */
  63. static Display *DispBase;  /*  list of displays    */
  64. static short   FlagRefresh;
  65.  
  66. static Config  ConfAry[MAXCONF];
  67.  
  68. Local int   HandleEvent(Display *, int *, int *);
  69. Local void  SaveWindowConfig(Display *);
  70. Local long  BackupFile(Display *, long, long);
  71. Local long  ForwardFile(Display *, long, long);
  72. Local void  SetRefresh(Display *, int);
  73.  
  74. #ifndef LATTICE
  75. extern void *OpenWindow();
  76. extern void *GetMsg();
  77. #endif
  78.  
  79. void *
  80. OpenBrowseDisplay(fileName, title, id)
  81. char *fileName;
  82. char *title;
  83. short id;
  84. {
  85.     static NewWindow Nw = {
  86.     0, 0, 320, 200, -1, -1,
  87.     CLOSEWINDOW|NEWSIZE|MOUSEBUTTONS|VANILLAKEY|REFRESHWINDOW,
  88.     WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|
  89.     SIMPLE_REFRESH|ACTIVATE,
  90.     NULL, NULL, NULL, NULL, NULL,
  91.     32, 16, -1, -1, WBENCHSCREEN
  92.     };
  93.     Display *disp = malloc(sizeof(Display));
  94.  
  95.     if (title == NULL)
  96.     title = fileName;
  97.  
  98.     setmem(disp, sizeof(Display), 0);
  99.  
  100.     if (id < 0 || id >= MAXCONF)
  101.     id = MAXCONF - 1;
  102.  
  103.     {
  104.     Config *conf = ConfAry + id;
  105.     Nw.LeftEdge = conf->LeftEdge;
  106.     Nw.TopEdge  = conf->TopEdge;
  107.     Nw.Width    = conf->Width;
  108.     Nw.Height   = conf->Height;
  109.     if (Nw.Width < 32) {
  110.         Nw.LeftEdge = 40;
  111.         Nw.Width = 600;
  112.     }
  113.     if (Nw.Height < 16)
  114.         Nw.Height = 150;
  115.     }
  116.  
  117.     disp->Win = OpenWindow(&Nw);
  118.     if (disp->Win == NULL) {
  119.     Nw.LeftEdge = 0;
  120.     Nw.TopEdge  = 0;
  121.     Nw.Width    = 320;
  122.     Nw.Height   = 100;
  123.     disp->Win = OpenWindow(&Nw);
  124.     }
  125.  
  126.     if (disp->Win) {
  127.     disp->Name = strdup(fileName);
  128.     disp->Title= strdup(title);
  129.     disp->WMask = 1 << disp->Win->UserPort->mp_SigBit;
  130.     disp->Id = id;
  131.  
  132.     SetAPen(disp->Win->RPort, 1);
  133.  
  134.     SetWindowTitles(disp->Win, disp->Title, (char *)-1L);
  135.  
  136.     disp->Next = DispBase;
  137.     DispBase = disp;
  138.  
  139.     WMask |= disp->WMask;
  140.  
  141.     SetRefresh(disp, 0);
  142.     if (disp->Fi = fopen(disp->Name, "r")) {
  143.         disp->FirstNonHdrLine = 0;
  144.         while (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi) && TmpBuf[0] != '\n')
  145.         ++disp->FirstNonHdrLine;
  146.     }
  147.     } else {
  148.     free(disp);
  149.     disp = NULL;
  150.     }
  151.     return((void *)disp);
  152. }
  153.  
  154. void
  155. SetBrowseTitle(_disp, title)
  156. void *_disp;
  157. char *title;
  158. {
  159.     Display *disp = _disp;
  160.     char *old = disp->Title;
  161.  
  162.     disp->Title = strdup(title);
  163.     SetWindowTitles(disp->Win, disp->Title, (char *)-1L);
  164.     free(old);
  165. }
  166.  
  167. void
  168. CloseBrowseDisplay(_disp)
  169. void *_disp;
  170. {
  171.     Display *disp = _disp;
  172.     Display *d;
  173.  
  174.     if (disp == CachDisp)
  175.     CachDisp = NULL;
  176.  
  177.     if (DispBase == disp) {                     /*  unlink display  */
  178.     DispBase = disp->Next;
  179.     } else {
  180.     for (d = DispBase; d; d = d->Next) {
  181.         if (d->Next == disp) {
  182.         d->Next = disp->Next;
  183.         break;
  184.         }
  185.     }
  186.     }
  187.  
  188.     SetWindowTitles(disp->Win, NULL, NULL);
  189.  
  190.     if (disp->Win) {
  191.     SaveWindowConfig(disp);
  192.     CloseWindow(disp->Win);
  193.     }
  194.  
  195.     WMask &= ~disp->WMask;
  196.  
  197.     free(disp->Title);
  198.     free(disp->Name);
  199.     if (disp->Fi)
  200.     fclose(disp->Fi);
  201.     free(disp);
  202. }
  203.  
  204. /*
  205.  *  Change file being displayed
  206.  */
  207.  
  208. void
  209. ChangeBrowseDisplay(_disp, fileName, title)
  210. void *_disp;
  211. char *fileName;
  212. char *title;
  213. {
  214.     Display *disp = _disp;
  215.     Window *win = disp->Win;
  216.  
  217.     if (title == NULL)
  218.     title = fileName;
  219.  
  220.     {
  221.     char *old = disp->Title;
  222.     disp->Title = strdup(title);
  223.     SetWindowTitles(disp->Win, disp->Title, (char *)-1L);
  224.     free(old);
  225.     }
  226.  
  227.     free(disp->Name);
  228.     disp->Name = strdup(fileName);
  229.     if (disp->Fi) {
  230.     fclose(disp->Fi);
  231.     disp->Fi = NULL;
  232.     }
  233.  
  234.     disp->TLineNo = 0;
  235.     disp->TPos = 0;
  236.     disp->XPos = 0;
  237.     disp->WLines = 0;
  238.     disp->WMaxLines = 0;
  239.     disp->FLines = 0;
  240.  
  241.     SetRefresh(disp, 0);
  242. }
  243.  
  244. /*
  245.  *  Wait for an event.    While waiting finish up scanning files for which we
  246.  *  do not know the line number extent.  Returns 0 if there are no windows
  247.  *  left.
  248.  */
  249.  
  250. int
  251. WaitBrowseEvent(_pdisp, prow, pcol)
  252. void **_pdisp;
  253. int *prow;
  254. int *pcol;
  255. {
  256.     long mask;
  257.     Display **pdisp = _pdisp;
  258.  
  259.     if (WMask == 0)
  260.     return(0);
  261.  
  262.     for (;;) {
  263.     Display *disp;
  264.  
  265.     if (FlagRefresh && (SetSignal(0,0) & WMask) == 0) {
  266.         for (disp = DispBase; disp; disp = disp->Next) {
  267.         if (disp->FlagRefresh)
  268.             RefreshBrowseDisplay(disp);
  269.         }
  270.         FlagRefresh = 0;
  271.     }
  272.     mask = Wait(WMask);
  273.     if ((disp = CachDisp) && (disp->WMask & mask)) {
  274.         mask &= ~disp->WMask;
  275.         if (HandleEvent(disp, prow, pcol))
  276.         goto event_handled;
  277.     }
  278.     if (mask) {
  279.         for (disp = DispBase; disp; disp = disp->Next) {
  280.         if (mask & disp->WMask) {
  281.             mask &= ~disp->WMask;
  282.             if (HandleEvent(disp, prow, pcol)) {
  283. event_handled:
  284.             *pdisp = disp;
  285.             if (GetHead(&disp->Win->UserPort->mp_MsgList))
  286.                 mask |= disp->WMask;
  287.             if (mask)
  288.                 SetSignal(mask, mask);
  289.             return(1);
  290.             }
  291.         }
  292.         }
  293.     }
  294.     }
  295. }
  296.  
  297. static int
  298. HandleEvent(disp, prow, pcol)
  299. Display *disp;
  300. int *prow;
  301. int *pcol;
  302. {
  303.     int ret = 0;
  304.     IMsg *im;
  305.     Window *win = disp->Win;
  306.  
  307.     while ((ret == 0) && (im = GetMsg(win->UserPort))) {
  308.     switch(im->Class) {
  309.     case CLOSEWINDOW:
  310.         *prow = -1;
  311.         *pcol = -1;
  312.         ret = 1;
  313.         break;
  314.     case VANILLAKEY:
  315.         switch(im->Code) {
  316.         case 13:
  317.         if (disp->BPos != disp->XPos) {
  318.             disp->TPos = ForwardFile(disp, disp->TPos, 2);
  319.             ++disp->TLineNo;
  320.             SetRefresh(disp, 0);
  321.         }
  322.         break;
  323.         case '2':       /*  page down   */
  324.         case ' ':
  325.         if (disp->BPos != disp->XPos) {
  326.             disp->TPos = disp->BPos;
  327.             disp->TLineNo += disp->WLines;
  328.             SetRefresh(disp, 0);
  329.         }
  330.         break;
  331.         case '8':       /*  page up   this article  */
  332.         if (disp->TPos != 0) {
  333.             disp->TPos = BackupFile(disp, disp->TPos, disp->WMaxLines);
  334.             disp->TLineNo -= disp->WMaxLines;
  335.             if (disp->TLineNo < 0)
  336.             disp->TLineNo = 0;
  337.             SetRefresh(disp, 0);
  338.         }
  339.         break;
  340.         case '3':
  341.         if (disp->BPos != disp->XPos) {
  342.             disp->TPos = BackupFile(disp, disp->XPos, disp->WLines);
  343.             disp->TLineNo = disp->FLines - disp->WLines;    /* XXX */
  344.             if (disp->TLineNo < 0)
  345.             disp->TLineNo = 0;
  346.             SetRefresh(disp, 0);
  347.         }
  348.         break;
  349.         case '9':
  350.         if (disp->TPos != 0) {
  351.             disp->TPos = 0;
  352.             disp->TLineNo = 0;
  353.             SetRefresh(disp, 0);
  354.         }
  355.         break;
  356.         case '6':
  357.         SetRefresh(disp, disp->ColStart + 40);
  358.         break;
  359.         case '4':
  360.         SetRefresh(disp, disp->ColStart - 40);
  361.         break;
  362.         default:
  363.         *prow = -1;
  364.         *pcol = im->Code;
  365.         ret = 1;
  366.         }
  367.         break;
  368.     case MOUSEBUTTONS:
  369.         if (im->Code == SELECTDOWN) {
  370.         *pcol = (im->MouseX - win->BorderLeft) / win->RPort->TxWidth;
  371.         *prow = ((im->MouseY - win->BorderTop) / win->RPort->TxHeight) + disp->TLineNo;
  372.         if (*prow >= 0)
  373.             ret = 1;
  374.         }
  375.         break;
  376.     case NEWSIZE:
  377.         SetRefresh(disp, 0);
  378.         break;
  379.     case REFRESHWINDOW:
  380.         BeginRefresh(win);
  381.         RefreshBrowseDisplay(disp);
  382.         EndRefresh(win, 1);
  383.         break;
  384.     default:
  385.         break;
  386.     }
  387.     ReplyMsg(im);
  388.     }
  389.     return(ret);
  390. }
  391.  
  392. void
  393. RefreshBrowseDisplay(vdisp)
  394. void *vdisp;
  395. {
  396.     Display *disp = (Display *)vdisp;
  397.     long x, y;
  398.     int maxx;
  399.     int dispLines = 0;
  400.     int lineNo;
  401.     Window *win = disp->Win;
  402.     short b;
  403.     short isHdr;
  404.     short rvsMode;
  405.  
  406.     disp->FlagRefresh = 0;
  407.     SetAPen(win->RPort, 0);
  408.     RectFill(win->RPort, win->BorderLeft, win->BorderTop, win->Width - win->BorderRight, win->Height - win->BorderBottom);
  409.     SetAPen(win->RPort, 1);
  410.  
  411.     if (disp->Fi == NULL) {
  412.     disp->Fi = fopen(disp->Name, "r");
  413.     if (disp->Fi == NULL)       /*  can't refresh if can't open file */
  414.         return;
  415.     fseek(disp->Fi, 0L, 2);
  416.     disp->XPos = ftell(disp->Fi);
  417.     }
  418.     if (ftell(disp->Fi) != disp->TPos)
  419.     fseek(disp->Fi, disp->TPos, 0);
  420.     lineNo = disp->TLineNo - 1;
  421.     x = win->BorderLeft;
  422.     y = win->BorderTop + win->RPort->TxBaseline;
  423.     maxx = (win->Width - win->BorderLeft - win->BorderRight) / win->RPort->TxWidth;
  424.  
  425.     b = 0;
  426.     TmpBuf[0] = 0;
  427.  
  428.     disp->WMaxLines = (win->Height - win->BorderBottom - win->BorderTop - 2) / win->RPort->TxHeight;
  429.  
  430.     while (y < win->Height - win->BorderBottom - 2) {
  431.     int len;
  432.  
  433.     if (TmpBuf[b] == 0) {
  434.         if (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi) == NULL)
  435.         break;
  436.         rvsMode = 0;
  437.         if (++lineNo < disp->FirstNonHdrLine) {
  438.         isHdr = 1;
  439.         if (strncmp(TmpBuf, "Subject:", 8) == 0)
  440.             rvsMode = 1;
  441.         } else {
  442.         isHdr = 0;
  443.         }
  444.         TabExpand(TmpBuf, sizeof(TmpBuf));
  445.         b = 0;
  446.     }
  447.     len = strlen(TmpBuf + b) - disp->ColStart;
  448.     if (len > maxx)
  449.         len = maxx;
  450.     if (len > 0) {
  451.         if (rvsMode) {
  452.         SetAPen(win->RPort, 0);
  453.         SetBPen(win->RPort, 1);
  454.         }
  455.         Move(win->RPort, x, y);
  456.         Text(win->RPort, TmpBuf + b + disp->ColStart, len);
  457.         if (rvsMode) {
  458.         SetAPen(win->RPort, 1);
  459.         SetBPen(win->RPort, 0);
  460.         }
  461.     }
  462.     ++dispLines;
  463.     y += win->RPort->TxHeight;
  464.     if (isHdr || disp->ColStart || len <= 0)
  465.         b = strlen(TmpBuf);
  466.     else
  467.         b += len;
  468.     }
  469.     disp->BPos = ftell(disp->Fi);
  470.     disp->WLines = dispLines;
  471. }
  472.  
  473. void
  474. LoadDisplayConfig()
  475. {
  476.     FILE *fi;
  477.  
  478.     if (fi = fopen("s:dnews.config", "r")) {
  479.     fread(ConfAry, 1, sizeof(ConfAry), fi);
  480.     fclose(fi);
  481.     }
  482. }
  483.  
  484. void
  485. SaveDisplayConfig()
  486. {
  487.     FILE *fi;
  488.  
  489.     if (fi = fopen("s:dnews.config", "w")) {
  490.     fwrite(ConfAry, 1, sizeof(ConfAry), fi);
  491.     fclose(fi);
  492.     }
  493. }
  494.  
  495. static void
  496. SaveWindowConfig(disp)
  497. Display *disp;
  498. {
  499.     Config *conf = ConfAry + disp->Id;
  500.     Window *win = disp->Win;
  501.  
  502.     conf->TopEdge   = win->TopEdge;
  503.     conf->LeftEdge  = win->LeftEdge;
  504.     conf->Width     = win->Width;
  505.     conf->Height    = win->Height;
  506. }
  507.  
  508. /*
  509.  *  Count lines forwards
  510.  */
  511.  
  512. static long
  513. ForwardFile(disp, pos, lines)
  514. Display *disp;
  515. long pos;
  516. long lines;
  517. {
  518.     long n;
  519.     long i;
  520.  
  521.     if (disp->Fi == NULL) {
  522.     disp->Fi = fopen(disp->Name, "r");
  523.     if (disp->Fi == NULL)
  524.         return(0);
  525.     }
  526.     fseek(disp->Fi, pos, 0);
  527.     while (lines) {
  528.     if (fgets(TmpBuf, sizeof(TmpBuf), disp->Fi) == NULL)
  529.         break;
  530.     --lines;
  531.     }
  532.     return(ftell(disp->Fi));
  533. }
  534.  
  535. /*
  536.  *  Count lines backwards
  537.  */
  538.  
  539. static long
  540. BackupFile(disp, pos, rlines)
  541. Display *disp;
  542. long pos;
  543. long rlines;
  544. {
  545.     long n;
  546.     long i;
  547.  
  548.     if (disp->Fi == NULL) {
  549.     disp->Fi = fopen(disp->Name, "r");
  550.     if (disp->Fi == NULL)
  551.         return(0);
  552.     }
  553.     ++rlines;    /*  think of the case where rlines is 1 in the below code   */
  554.  
  555.     while (rlines && pos) {
  556.     n = sizeof(TmpBuf);
  557.     if (pos < n)
  558.         n = pos;
  559.     fseek(disp->Fi, pos - n, 0);
  560.     fread(TmpBuf, 1, n, disp->Fi);
  561.     for (i = n - 1; i >= 0; --i) {
  562.         if (TmpBuf[i] == '\n') {
  563.         if (--rlines == 0)
  564.             break;
  565.         }
  566.     }
  567.     ++i;
  568.     pos = pos - n + i;
  569.     }
  570.     return(pos);
  571. }
  572.  
  573. /*
  574.  *  Flag that the display should be refreshed without doing so immediately.
  575.  *  This allows the user to skip around articles without having to wait
  576.  *  for the display to catch up.
  577.  */
  578.  
  579. static void
  580. SetRefresh(disp, lrc)
  581. Display *disp;
  582. int lrc;
  583. {
  584.     FlagRefresh = 1;
  585.  
  586.     if (lrc < 0)
  587.     lrc = 0;
  588.  
  589.     if (lrc > TMPBSIZE - 1)
  590.     lrc = TMPBSIZE - 1;
  591.  
  592.     disp->FlagRefresh = 1;
  593.     disp->ColStart = lrc;
  594. }
  595.  
  596.  
  597. /*
  598.  *                YES OR NO
  599.  */
  600.  
  601. typedef struct IntuiText    ITEXT;
  602. typedef unsigned char    ubyte;
  603.  
  604. int
  605. getyn(text)
  606. char *text;
  607. {
  608.     int result;
  609.     ITEXT *body, *pos, *neg;
  610.  
  611.     if (DispBase == NULL)
  612.     return(0);
  613.  
  614.     body = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
  615.     pos  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
  616.     neg  = (ITEXT *)AllocMem(sizeof(ITEXT), 0);
  617.     setmem(body, sizeof(ITEXT), 0);
  618.     setmem(pos , sizeof(ITEXT), 0);
  619.     setmem(neg , sizeof(ITEXT), 0);
  620.     body->BackPen = pos->BackPen = neg->BackPen = 1;
  621.     body->DrawMode= pos->DrawMode= neg->DrawMode= AUTODRAWMODE;
  622.     body->LeftEdge = 10;
  623.     body->TopEdge  = 12;
  624.     body->IText    = (ubyte *)text;
  625.     pos->LeftEdge = AUTOLEFTEDGE;
  626.     pos->TopEdge = AUTOTOPEDGE;
  627.     pos->IText = (ubyte *)"OK";
  628.     neg->LeftEdge = AUTOLEFTEDGE;
  629.     neg->TopEdge = AUTOTOPEDGE;
  630.     neg->IText = (ubyte *)"CANCEL";
  631.     result = AutoRequest(DispBase->Win, body, pos, neg, 0, 0, 320, 58);
  632.     FreeMem(body, sizeof(ITEXT));
  633.     FreeMem(pos , sizeof(ITEXT));
  634.     FreeMem(neg , sizeof(ITEXT));
  635.     return(result);
  636. }
  637.  
  638. void
  639. TabExpand(buf, max)
  640. char *buf;
  641. short max;
  642. {
  643.     short i;
  644.     short len = strlen(buf);
  645.     char *ptr;
  646.  
  647.     max -= 9;
  648.     for (i = 0, ptr = buf; *ptr; ++ptr, ++i) {
  649.     if (*ptr == '\n') {
  650.         *ptr = 0;
  651.         break;
  652.     }
  653.     if (*ptr == 9 && len < max) {
  654.         int n = ~i & 7;
  655.         movmem(ptr, ptr + n, len - i + 1);
  656.         setmem(ptr, n + 1, ' ');
  657.         len += n;
  658.     }
  659.     }
  660. }
  661.  
  662.